package judesart.app.client.ui.admin.project;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import judesart.app.client.controller.ProjectController;
import judesart.app.client.controller.ProjectControllerAsync;
import judesart.app.client.widget.TopInfo;
import judesart.app.domain.Note;
import judesart.app.domain.Project;

import com.allen_sauer.gwt.log.client.Log;
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.data.BaseListLoadConfig;
import com.extjs.gxt.ui.client.data.BaseListLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ListLoadResult;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.data.MemoryProxy;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Composite;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.ListView;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.TextArea;
import com.extjs.gxt.ui.client.widget.form.FormPanel.LabelAlign;
import com.extjs.gxt.ui.client.widget.layout.FormData;
import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class NotesPanel extends Composite
{
    ProjectControllerAsync service = GWT.create(ProjectController.class);
    private final LayoutContainer notesLayoutContainer;
    private Project project;
    private final List<Note> notes = new ArrayList<Note>();
    private final ListLoader<ListLoadResult<Note>> loader;
    private final TextArea txtrNewNote;
    private final Button btnAdd;
    private final Button btnSave;
    private final Button btnDelete;
    private final Button btnCancel;
    private Note note;

    public NotesPanel(Project project)
    {
        setProject(project);
        notesLayoutContainer = new LayoutContainer();
        notesLayoutContainer.setWidth(798);
        notesLayoutContainer.setAutoHeight(true);
        notesLayoutContainer.setBorders(false);

        MemoryProxy<List<Note>> proxy = new MemoryProxy<List<Note>>(notes);

        loader = new BaseListLoader<ListLoadResult<Note>>(proxy,
                new BeanModelReader());
        ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
        loader.load();

        final ListView<BeanModel> notesListView = new ListView<BeanModel>(store)
        {
            @Override
            protected BeanModel prepareData(BeanModel model)
            {
                model.set("createdAtFormated",
                        format((Date) model.get("createdAt")));
                return model;
            }
        };
        notesListView.setLoadingText("loading...");
        notesListView.setBorders(false);
        notesListView.setTemplate(getTemplate());
        notesListView.setItemSelector("div.thumb-wrap");
        notesListView.getSelectionModel().addListener(Events.SelectionChange,
                new Listener<SelectionChangedEvent<BeanModel>>()
                {
                    public void handleEvent(SelectionChangedEvent<BeanModel> be)
                    {
                        onSelectionChanged(be);
                    }
                });
        notesListView.setHeight(300);

        notesLayoutContainer.add(notesListView);

        FormPanel frmpnlAddnote = new FormPanel();
        frmpnlAddnote.setLabelAlign(LabelAlign.TOP);
        frmpnlAddnote.setLabelSeparator("");
        frmpnlAddnote.setHeaderVisible(false);
        frmpnlAddnote.setHeading("AddNote");

        txtrNewNote = new TextArea();
        txtrNewNote.setMaxLength(500);
        frmpnlAddnote.add(txtrNewNote, new FormData("100%"));

        btnAdd = new Button("Add Note");
        btnAdd.addSelectionListener(new SelectionListener<ButtonEvent>()
        {
            @Override
            public void componentSelected(ButtonEvent ce)
            {
                addNewNote();
            }
        });
        frmpnlAddnote.addButton(btnAdd);
        btnSave = new Button("Save");
        btnSave.addSelectionListener(new SelectionListener<ButtonEvent>()
        {
            @Override
            public void componentSelected(ButtonEvent ce)
            {
                saveNote();
            }
        });
        btnSave.setVisible(false);
        frmpnlAddnote.addButton(btnSave);
        btnDelete = new Button("Delete");
        btnDelete.addSelectionListener(new SelectionListener<ButtonEvent>()
        {
            @Override
            public void componentSelected(ButtonEvent ce)
            {
                deleteNote();
            }
        });
        btnDelete.setVisible(false);
        frmpnlAddnote.addButton(btnDelete);
        btnCancel = new Button("Cancel");
        btnCancel.addSelectionListener(new SelectionListener<ButtonEvent>()
        {
            @Override
            public void componentSelected(ButtonEvent ce)
            {
                cancelNote();
            }
        });
        btnCancel.setVisible(false);
        frmpnlAddnote.addButton(btnCancel);
        frmpnlAddnote.setButtonAlign(HorizontalAlignment.RIGHT);
        notesLayoutContainer.add(frmpnlAddnote);

        initComponent(notesLayoutContainer);
    }

    private void editNote(Note note)
    {
        this.note = note;
        btnAdd.setVisible(false);
        btnSave.setVisible(true);
        btnDelete.setVisible(true);
        btnCancel.setVisible(true);
        txtrNewNote.setValue(note.getText());
    }

    private void saveNote()
    {
        note.setText(txtrNewNote.getValue());
        service.updateNoteInProject(note, new AsyncCallback<Void>()
        {
            @Override
            public void onFailure(Throwable caught)
            {
                TopInfo.display("Error", "Unable to update note");
                Log.error("Error updating note", caught);
            }

            @Override
            public void onSuccess(Void result)
            {
                TopInfo.display("Info", "Note updated");
                loader.load();
                cancelNote();
            }
        });
    }

    private void deleteNote()
    {
        service.deleteNoteFromProject(project.getId(), note.getKey(),
                new AsyncCallback<Void>()
                {
                    @Override
                    public void onFailure(Throwable caught)
                    {
                        Log.error("Error deleting note", caught);
                        TopInfo.display("Error", "Unable to delete note");
                    }

                    @Override
                    public void onSuccess(Void result)
                    {
                        TopInfo.display("Info", "Note deleted");
                        notes.remove(note);
                        loader.load();
                        cancelNote();
                    }
                });
    }

    private void cancelNote()
    {
        this.note = null;
        btnAdd.setVisible(true);
        btnSave.setVisible(false);
        btnDelete.setVisible(false);
        btnCancel.setVisible(false);
        txtrNewNote.setValue(null);
    }

    private String format(Date createdAt)
    {
        Date now = new Date();
        String format;
        if (createdAt.getTime() > now.getTime() - 12 * 60 * 60 * 1000)
        {
            format = "HH:mm";
        } else
        {
            if (createdAt.getTime() > now.getTime() - 365 * 24 * 60 * 60 * 1000)
            {
                format = "dd/MMM";
            } else
            {
                format = "dd/MM/yy";
            }
        }
        String formated = DateTimeFormat.getFormat(format).format(createdAt);
        return formated;
    }

    private void addNewNote()
    {
        txtrNewNote.setEnabled(false);
        btnAdd.setEnabled(false);
        service.addNoteToProject(project.getId(), txtrNewNote.getValue(),
                new AsyncCallback<Note>()
                {

                    @Override
                    public void onSuccess(Note result)
                    {
                        txtrNewNote.setValue(null);
                        notes.add(0, result);
                        loader.load();
                        txtrNewNote.setEnabled(true);
                        btnAdd.setEnabled(true);
                    }

                    @Override
                    public void onFailure(Throwable caught)
                    {
                        Log.error("Error adding note to project", caught);
                        TopInfo.display("Error", "Unable to add note");
                        txtrNewNote.setEnabled(true);
                        btnAdd.setEnabled(true);
                    }
                });
    }

    protected Project getProject()
    {
        return project;
    }

    protected void setProject(Project project)
    {
        this.project = project;
        notes.clear();
        if (project != null && project.getNotes() != null
                && project.getNotes().size() > 0)
        {
            notes.addAll(project.getNotes());
        }
        Collections.sort(notes, new Comparator<Note>()
        {
            @Override
            public int compare(Note o1, Note o2)
            {
                return o2.getCreatedAt().compareTo(o1.getCreatedAt());
            }
        });
    }

    protected void openProject(Project project)
    {
        setProject(project);
        loader.load(new BaseListLoadConfig());
    }

    private native String getTemplate() /*-{
        return ['<tpl for=".">', 
        '<div style="border: 1px solid #FFFFFF;margin:4px 0 4px  4px; padding:2px;" class="thumb-wrap" id="{key}">', 
        '<div style="width: 40px; margin-right: 10px; float: left;">{createdAtFormated}</div>', 
        '<span style="width: 100%; text-align: left; color: #999999;">{text}</span>',
        '</div>',
        '</tpl>', 
        '<div class="x-clear"></div>'].join("");
    }-*/;

    private void onSelectionChanged(SelectionChangedEvent<BeanModel> be)
    {
        Object source = be.getSource();
        Log.debug("source [" + source + "]");
        if (be.getSelection().size() == 0)
        {
            return;
        }
        final BeanModel model = be.getSelection().get(0);
        editNote((Note) model.getBean());
    }

}
